package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
)

func DecHex(n int64) string {
	if n == 0 {
		return "0"
	}
	hex := map[int64]int64{10: 65, 11: 66, 12: 67, 13: 68, 14: 69, 15: 70}
	s := ""
	for q := n; q > 0; q = q / 16 {
		m := q % 16
		if m > 9 && m < 16 {
			m = hex[m]
			s = fmt.Sprintf("%v%v", string(m), s)
			continue
		}
		s = fmt.Sprintf("%v%v", m, s)
	}
	return s
}
func printHelp() {
	// 输出提示信息
	fmt.Printf("usage: check [md5|sha1|sha256|sha512|etag|qEtag] file\n\n")
	fmt.Printf("  %4s: %s\n", "md5", "计算文件md5值")
	fmt.Printf("  %4s: %s\n", "sha1", "计算文件sha1值")
	fmt.Printf("  %4s: %s\n", "sha256", "计算文件sha256值")
	fmt.Printf("  %4s: %s\n", "sha512", "计算文件sha512值")
	fmt.Printf("  %4s: %s\n", "etag", "计算文件etag(unixtime-filesize)值")
	fmt.Printf("  %4s: %s\n", "qEtag", "计算文件qEtag值")
}
func main() {
	// 判断是否存在参数
	if len(os.Args) < 3 {
		printHelp()
		return
	}
	// 读取文件
	f, err := os.Open(os.Args[2])
	if err != nil {
		fmt.Printf("文件读取失败,请检查文件路径是否存在！\n")
		return
	}

	buf := make([]byte, 1024*1024*16*16)
	switch strings.ToLower(os.Args[1]) {
	case "md5":
		h := md5.New()
		for {
			n, err := f.Read(buf)
			h.Write(buf[:n])
			if err == io.EOF {
				break
			}
		}
		fmt.Printf("%x\n", h.Sum(nil))
	case "sha1":
		h := sha1.New()
		for {
			n, err := f.Read(buf)
			h.Write(buf[:n])
			if err == io.EOF {
				break
			}
		}
		fmt.Printf("%x\n", h.Sum(nil))
	case "sha256":
		h := sha256.New()
		for {
			n, err := f.Read(buf)
			h.Write(buf[:n])
			if err == io.EOF {
				break
			}
		}
		fmt.Printf("%x\n", h.Sum(nil))
	case "sha512":
		h := sha512.New()
		for {
			n, err := f.Read(buf)
			h.Write(buf[:n])
			if err == io.EOF {
				break
			}
		}
		fmt.Printf("%x\n", h.Sum(nil))
	case "etag":
		fileInfo, _ := os.Stat(os.Args[2])
		//文件大小
		filesize := fileInfo.Size()
		//修改时间
		modTime := fileInfo.ModTime()
		etag := DecHex(modTime.Unix()) + "-" + strconv.FormatInt(filesize, 16)
		fmt.Println(strings.ToLower(etag)) //返回的是字节
	case "qetag":
		etag, err := GetEtag(f)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
		fmt.Println(etag)
	default:
		fmt.Println(etag)
		printHelp()
	}
}
